package com.example.demo.utils;

import cn.hutool.core.util.StrUtil;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.IntStream;

@SuppressWarnings("unused")
public class NumberUtils {

    /**
     * 定义需要判断的数据类型
     */
    private static final String FLOAT = "class java.lang.Float";
    private static final String DOUBLE = "class java.lang.Double";
    private static final String BIG_DECIMAL = "class java.math.BigDecimal";
    private static final Set<String> SET_OF_CLASS = new HashSet<String>() {{
        this.add(FLOAT);
        this.add(DOUBLE);
        this.add(BIG_DECIMAL);
    }};


    /**
     * Reserved decimal place.
     *
     * @param <T>   the type parameter
     * @param t     the t
     * @param place the place
     */
    public static <T> void reservedDecimalPlace(T t, int place) {
        // 获取对象t的所有属性
        Field[] field = t.getClass().getDeclaredFields();

        // 遍历所有属性
        IntStream.range(0, field.length).forEach(index -> {
            // 获取属性的名字
            String name = field[index].getName();

            // 将属性的首字符大写，方便构造get，set方法
            name = name.substring(0, 1).toUpperCase() + name.substring(1);

            // 获取属性的类型
            String type = field[index].getGenericType().toString();

            // 判断是否为定义的类型
            if (SET_OF_CLASS.contains(type)) {
                try {
                    typeJudgment(field[index], type, t, name, place);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        });
    }

    public static <T> void typeJudgment(Field field, String dataType, T t, String attributeName, int place) throws Exception {
        // 打开字段权限
        field.setAccessible(true);

        // 获得get方法
        Method getMethod = t.getClass().getMethod("get" + attributeName);

        // 获得要强转的类型
        Class<?> aClass = Class.forName(dataType.substring(6));

        // 通过get()方法获得字段值
        Object invoke = getMethod.invoke(t);

        // 类型强转
        Object castType = aClass.cast(invoke);

        //使用set方法重新给字段赋值
        if (castType instanceof Float) {
            field.set(t, transformDouble(castType, FLOAT, place).floatValue());
        }

        if (castType instanceof Double) {
            field.set(t, transformDouble(castType, DOUBLE, place).doubleValue());
        }

        if (castType instanceof BigDecimal) {
            field.set(t, transformDouble(castType, BIG_DECIMAL, place));
        }
    }

    public static <T> BigDecimal transformDouble(T t, String type, int placeNum) {
        java.math.BigDecimal decimal = null;

        switch (type) {
            case FLOAT:
                decimal = java.math.BigDecimal.valueOf((Float) t);
                break;
            case DOUBLE:
                decimal = java.math.BigDecimal.valueOf((Double) t);
                break;
            case BIG_DECIMAL:
                decimal = ((BigDecimal) t);
                break;
            default:
                break;
        }

        return null != decimal ? decimal.setScale(placeNum, RoundingMode.HALF_UP) : new BigDecimal(0);
    }



    /**
     * Scientific notation to double number double.
     *
     * @param num the num
     * @return the double
     */
    public static String scientificNotationToDoubleNumber(Double num){
        if (StrUtil.containsIgnoreCase(num.toString(),"E")){
            BigDecimal bigDecimal = new BigDecimal(num.toString());
            String strNum = bigDecimal.toPlainString();
            return StrUtil.endWith(strNum,"0")?strNum.substring(0,strNum.length()-1):strNum;
        }

        return null;
    }

}
